using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Generic;

// FIXME: We are using our own UnixClient and UnixListener
// from Dashboard.Util until the patch for 2.0 has been
// accepted upstream.
//using Mono.Unix;

using Dashboard;
using Dashboard.Util;
using Dashboard.Engine;

namespace Dashboard.Engine.Transports
{
	public class UnixTransport : IComponent
	{
		private UnixListener listener = null;
		private Thread thread = null;

		private bool running = false;

		private List<UnixConnectionHandler> handlers = new List<UnixConnectionHandler> ();
		
		public void Initialize ()
		{
			string socket_path = Path.Combine (PathFinder.UserData, "dashboard");

			try {
				listener = new UnixListener (socket_path);
			} catch (SocketException ex) {
				Engine.Log.Error ("Could not start UNIX listener: {0}", ex.Message);
				throw;
			}

			thread = new Thread (new ThreadStart (Worker));
			thread.Start ();
		}
		
		public void Dispose ()
		{
			running = false;
			listener.Stop ();
		}

		private void Worker ()
		{
			listener.Start ();
			running = true;
			
			while (running) {
				UnixClient client;
				
				try {
					// This will block for an incoming connection.
					// FIXME: But not really, it'll only wait a second.
					// see the FIXME in UnixListener for more info.
					client = listener.AcceptUnixClient ();
				} catch (SocketException) {
					// If the listener is stopped while we
					// wait for a connection, a SocketException is thrown.
					break;
				}
				
				if (client == null)
					continue;
				
				UnixConnectionHandler handler = new UnixConnectionHandler (client);
				handler.Start ();

				// FIXME: Keep track of running handlers
				// so that we can cancel them when we
				// get disposed.
				handlers.Add (handler);
			}
		}

		private class UnixConnectionHandler : XmlConnectionHandler
		{
			private bool running;
			private UnixClient client;

			public UnixConnectionHandler (UnixClient client)
			{
				this.client = client;
			}

			protected override Stream Stream {
				get { return client.GetStream (); }
			}

			// FIXME: Same trouble as with TcpClient,
			// but cant use the workaround since UnixClient
			// has the Client property marked as protected :-(
			// NOTE: A patch has been sent upstream to make
			// UnixClient more ala TcpClient on 2.0
			protected override bool Closed {
				get { return (client == null || (client.Client.Poll (10, SelectMode.SelectRead)
							       && client.Client.Available == 0));
				}
			}

			public override void Close ()
			{
				if (client == null)
					return;
				
				client.Close ();
				client = null;
			}
		}

		public string Name
		{
			get { return "UnixTransport"; }
		}

		public string Description
		{
			get { return "Transports messages to and from the engine via UNIX domain sockets"; }
		}
	}
}
